package obj;

import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Group;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.vecmath.Matrix4f;
import javax.vecmath.Vector3f;

import outils.Constantes;
import outils.Materiaux;
import phyzik.solides.PhysiqueBarre;
import phyzik.solides.PhysiqueSolide;
import struct.Intervalle;
import struct.Matrice4;

import com.sun.j3d.utils.geometry.Cylinder;
import com.sun.j3d.utils.geometry.Primitive;

public class Barre implements Objet {
	protected BranchGroup barre;
	protected TransformGroup groupeMobile;
	protected TransformGroup groupeJoueurs;
	protected TransformGroup groupeFixe;
	protected Transform3D transf3D;

	protected TransformGroup Mouvement;

	protected Cylinder cy;
	protected Cylinder cyFixe;
	protected Cylinder cyBout;
	protected Appearance apparenceCyMobile;
	protected Appearance apparenceCyFixe;
	protected Appearance apparenceCyBout;

	protected float longueur;
	protected float rayon;

	protected int eq;

	public PhysiqueBarre physique;

	public float[] limites;
	public Intervalle I;

	public Matrix4f transformationPrecedente;
	public Matrix4f transformation;

	protected Joueur[] joueurs;
	protected int equipe;

	public Barre(int eq, int num, int j, float lim1, float lim2) {
		physique = new PhysiqueBarre(eq, num);
		this.eq = eq;
		this.limites = new float[2];
		limites[0] = lim1;
		limites[1] = lim2;
		this.I = new Intervalle(limites[0], limites[1]);
		this.equipe = eq;
		joueurs = new Joueur[j];

		barre = new BranchGroup();

		apparence();
		construire();

		barre.compile();
	}

	public BranchGroup getObjet() {
		return barre;
	}

	public Joueur maitre() {
		return joueurs[0];
	}

	public Joueur[] getJoueurs() {
		return joueurs;
	}

	public PhysiqueSolide getPhysique() {
		return physique;
	}

	public void setPhysique(PhysiqueSolide ps) {
		this.physique = (PhysiqueBarre) ps;
	}

	public float[] getLimites() {
		return limites;
	}

	public void apparence() {
		apparenceCyMobile = new Appearance();
		apparenceCyMobile.setCapability(Appearance.ALLOW_MATERIAL_READ);
		apparenceCyMobile.setCapability(Appearance.ALLOW_MATERIAL_WRITE);
		apparenceCyMobile.setMaterial(Materiaux.ALU);
		apparenceCyFixe = new Appearance();
		apparenceCyFixe.setMaterial(Materiaux.ACIER);
		apparenceCyBout = new Appearance();
		apparenceCyBout.setMaterial(Materiaux.matAlea());
	}

	public void desactiver() {
		apparenceCyMobile.setMaterial(Materiaux.ALU);
	}

	public void activer() {
		apparenceCyMobile.setMaterial(Materiaux.matAlea());
	}

	public void construire() {
		transf3D = new Transform3D();
		transf3D.set(physique.getTransformation());

		groupeFixe = new TransformGroup(transf3D);
		groupeMobile = new TransformGroup(transf3D);
		groupeMobile.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
		groupeMobile.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		groupeMobile.setCapability(Group.ALLOW_CHILDREN_EXTEND);

		barre.addChild(groupeMobile);
		barre.addChild(groupeFixe);

		ajouterCylindreMobile();
		ajouterCylindreFixe();
		ajouterJoueurs();

		transformationPrecedente = new Matrix4f(Matrice4.identite());
		transformation = new Matrix4f(physique.getTransformation());
	}

	public void ajouterCylindreMobile() {
		Transform3D rotationCylindre = new Transform3D();
		TransformGroup groupeCylindre = new TransformGroup(rotationCylindre);
		cy = new Cylinder(1.2f * Constantes.RAYON_BARRE,
				Constantes.LONGUEUR_BARRE, Primitive.GENERATE_NORMALS
						| Primitive.GENERATE_TEXTURE_COORDS, apparenceCyMobile);
		groupeCylindre.addChild(cy);
		groupeMobile.addChild(groupeCylindre);

		Transform3D cylindreBout = new Transform3D();
		cylindreBout.setTranslation(new Vector3f(0f, -eq
				* (Constantes.LONGUEUR_BARRE + Constantes.LONGUEUR_BOUT) / 2,
				0f));
		TransformGroup groupeCylindreBout = new TransformGroup(cylindreBout);
		cyBout = new Cylinder(2.5f * Constantes.RAYON_BARRE,
				Constantes.LONGUEUR_BOUT, Primitive.GENERATE_NORMALS
						| Primitive.GENERATE_TEXTURE_COORDS, apparenceCyBout);
		groupeCylindreBout.addChild(cyBout);
		groupeMobile.addChild(groupeCylindreBout);
	}

	public void ajouterCylindreFixe() {
		Transform3D rotationCylindreFixe = new Transform3D();
		TransformGroup groupeCylindreFixe = new TransformGroup(
				rotationCylindreFixe);
		cyFixe = new Cylinder(Constantes.RAYON_BARRE,
				Constantes.LONGUEUR_BARRE, Primitive.GENERATE_NORMALS
						| Primitive.GENERATE_TEXTURE_COORDS, apparenceCyFixe);
		groupeCylindreFixe.addChild(cyFixe);
		groupeFixe.addChild(groupeCylindreFixe);
	}

	public void ajouterJoueurs() {
		Transform3D translationJoueurs = new Transform3D();
		TransformGroup groupeJoueurs = new TransformGroup(translationJoueurs);
		barre.addChild(groupeJoueurs);
		int debut = 0;
		switch (joueurs.length) {
		case 1:
			debut = 0;
			break;
		case 2:
			debut = 1;
			break;
		case 3:
			debut = 7;
			break;
		case 4:
			debut = 3;
			break;
		}
		for (int k = 0; k < joueurs.length; k++) {
			joueurs[k] = new Joueur(equipe, k + debut, this);
			groupeJoueurs.addChild(joueurs[k].getObjet());
		}
	}

	public void deplacer() {
		groupeMobile.getTransform(transf3D);
		Transform3D Mouvement = new Transform3D();

		transformationPrecedente.set(transformation);
		transformationPrecedente.invert();

		transformation.set(physique.getTransformation());

		Matrix4f temp = new Matrix4f(transformationPrecedente);
		temp.mul(transformation);

		Mouvement.set(temp);
		transf3D.mul(Mouvement);
		groupeMobile.setTransform(transf3D);
	}
}
